/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    crg.h
 *  @brief   CRG header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 ****************************************************************/

#ifndef __CRG_H__
#define __CRG_H__

#include <stdint.h>
#include <stdbool.h>

#include "eocv100.h"
#include "bits.h"
#include "io.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct crg_reg crg_reg_t, *crg_reg_t_ptr;
typedef uint32_t clk_freq;

#define CLK_FREQ_200MHZ        (200000000UL)
#define CLK_FREQ_100MHZ        (100000000UL)
#define CLK_FREQ_50MHZ         (50000000UL)
#define CLK_FREQ_30MHZ         (30000000UL)
#define CLK_FREQ_25MHZ         (25000000UL)
#define CLK_FREQ_15MHZ         (15000000UL)
#define CLK_FREQ_7_5MHZ        (7500000UL)
#define CLK_FREQ_3_75MHZ       (3750000UL)
#define CLK_FREQ_500KHZ        (500000UL)
#define CLK_FREQ_32KHZ         (32000UL)
#define CLK_FREQ_46875HZ       (46875UL)

#define SOC_CRG_BASE_ADDR      MEM_MAP_CRG_BASE_ADDR

#define SOC_PLL_PREDIV_POS     0
#define SOC_PLL_PREDIV_LEN     5
#define SOC_PLL_N_POS          5
#define SOC_PLL_N_LEN          9
#define SOC_PLL_M_POS          14
#define SOC_PLL_M_LEN          2

#define SOC_PLL1_FRADIV_POS    0
#define SOC_PLL1_FRADIV_LEN    21

#define SOC_PLL3_POSTDIV_POS   4
#define SOC_PLL3_POSTDIV_LEN   2

/* writes b'1 to reset PLL */
#define LOCAL_SOC_PLL_RESET    BIT(24)

/* writes b'0 to reset global */
#define LOCAL_GLOBAL_RESET     BIT(0)

#define PLL_CPU_CLK_DIV_POS    0
#define PLL_CPU_CLK_DIV_LEN    8
#define PLL_APB_CLK_DIV_POS    8
#define PLL_APB_CLK_DIV_LEN    8
#define PLL_SD_CLK_DIV_POS     16
#define PLL_SD_CLK_DIV_LEN     8
#define PLL_SAR_CLK_DIV_POS    24
#define PLL_SAR_CLK_DIV_LEN    8

#define PLL_BUS_HCLK_DIV_POS   0
#define PLL_BUS_HCLK_DIV_LEN   8
#define PLL_HAC_CLK_DIV_POS    8
#define PLL_HAC_CLK_DIV_LEN    8
#define PLL_TIMER_CLK_DIV_POS  16
#define PLL_TIMER_CLK_DIV_LEN  8
#define PLL_SENSOR_CLK_DIV_POS 24
#define PLL_SENSOR_CLK_DIV_LEN 8

#define SOC_PLL_SEL_POS        1
#define SOC_PLL_SEL_LEN        1
#define SOC_SWITCH_SEL_POS     0
#define SOC_SWITCH_SEL_LEN     1


/* writes b'1 to reset ADC */
#define LOCAL_SD_ADC_RESET     BIT(23)
#define LOCAL_SAR_ADC_RESET    BIT(24)

/* pll has locked */
#define SOC_PLL_LOCK_STA       BIT(1)

/*clk alram stat*/
#define CLK_XTAL24M_ALARM      BIT(0)
#define CLK_XTAL32K_ALARM      BIT(1)
#define CLK_PLL_ALARM          BIT(2)


#define SOC_REF_CLK_ERR_POS    0
#define SOC_REF_CLK_ERR_LEN    8
#define SOC_PLL_CLK_ERR_POS    8
#define SOC_PLL_CLK_ERR_LEN    8
#define SOC_OSC_CLK_ERR_POS    16
#define SOC_OSC_CLK_ERR_LEN    8

#define WDT_RST_COUNTER_POS    0
#define WDT_RST_COUNTER_LEN    5
#define LOCKUP_RST_COUNTER_POS 5
#define LOCKUP_RST_COUNTER_LEN 5

#define CLK_ARLARM_POS         0
#define CLK_ARLARM_LEN         3

#define CLK_MON_MUX_POS        24
#define CLK_MON_MUX_LEN        3

#define CRG_REG_PTR()          ((crg_reg_t_ptr)SOC_CRG_BASE_ADDR)

enum pll_sel {
	CLK_PLL_OUT,
	CLK_24M,
};

enum switch_sel {
	CLK_24M_32K,
	CLK_PLL_MUX,
};

enum clk_mon {
	CLK_OSC32K,
	CLK_XTAL24M,
	CLK_PLL,
	CLK_RVS,
	CLK_XTAL32K,
};


struct crg_reg {
	__IOM reg_t soc_pll0;        /* 0x00, pll clock configure */
	__IOM reg_t soc_pll1;        /* 0x04, pll clock configure, clock switch */
	__IOM reg_t reset;           /* 0x08, peripheral rese*/
	__IOM reg_t apb_reset;       /* 0x0c, APB reset */
	__IOM reg_t clkdiv;          /* 0x10, core, apb, adc clock divider */
	__IOM reg_t busclkdiv;       /* 0x14, bus  hac timer tsensor clock divider */
	__IOM reg_t gate;            /* 0x18, clock gate */
	__IM  reg_t pllsta;          /* 0x1c, pll lock status */
	__IOM reg_t clk_monitor;     /* 0x20, clock observation */
	__IOM reg_t soc_pll2;        /* 0x24, pll select, switch select*/
	__IM  reg_t clk_alm_monitor; /* 0x28, pll, 32k, 24M clk alarm sta*/
	__IOM reg_t soc_pll3;        /* 0x2C, pll config fefault is ok*/
	__IOM reg_t rst_count;       /* 0x30, wdt, lockup rst counter*/
	__IOM reg_t lockup_bypass;   /* 0x34, lockup rst bypass*/
	__IOM reg_t dfs_ctrl;        /* 0x38, dfs enable divide*/
	__IOM reg_t dfs_count;       /* 0x3C, dfs count*/
	__OM  reg_t dfs_req;         /* 0x40, dfs req*/
	__IOM reg_t xtal24m_cfg;     /* 0x44, xtal24m_cfg*/
	__IOM reg_t xtal32k_cfg;     /* 0x48, xtal32k_cfg*/
	__IOM reg_t glb_reset;       /* 0x4C global reset*/
	
};

enum crg_mod {
	CRG_MOD_CPU_CORE,
	CRG_MOD_UART0,
	CRG_MOD_UART1,
	CRG_MOD_UART2,
	CRG_MOD_UART3,
	CRG_MOD_UART4,
	CRG_MOD_WDT1,
	CRG_MOD_TIMER,
	CRG_MOD_TIMER0,
	CRG_MOD_TIMER1,
	CRG_MOD_TIMER2,
	CRG_MOD_TIMER3,
	CRG_MOD_TIMER4,
	CRG_MOD_TIMER5,
	CRG_MOD_TIMER6,
	CRG_MOD_TIMER7,
	CRG_MOD_SPI0,
	CRG_MOD_SPI1,
	CRG_MOD_SPI2,
	CRG_MOD_SPI3,
	CRG_MOD_I2C0,
	CRG_MOD_I2C1,
	CRG_MOD_GPIO0,
	CRG_MOD_DMA,
	CRG_MOD_SD_ADC,
	CRG_MOD_SAR_ADC,

	CRG_MOD_SYSCNT,
	CRG_MOD_TSENSOR,
	CRG_MOD_PMU,
	CRG_MOD_RTC,
	CRG_MOD_WDT0,
};

void     pll_clk_mon(enum clk_mon mon);
int32_t  pll_init(void);
clk_freq get_mod_clk_rate(enum crg_mod mod);
void global_reset(void);
#ifdef __cplusplus
}
#endif

#endif /* __CRG_H__ */

